package com.sdhs.workflow.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sdhs.common.core.domain.entity.SysUser;
import com.sdhs.common.core.domain.event.ProcessEvent;
import com.sdhs.common.core.domain.event.ProcessTaskEvent;
import com.sdhs.common.core.page.PageQuery;
import com.sdhs.common.core.page.TableDataInfo;
import com.sdhs.common.enums.BusinessStatusEnum;
import com.sdhs.common.exception.ServiceException;
import com.sdhs.common.utils.SecurityUtils;
import com.sdhs.common.utils.StreamUtils;
import com.sdhs.common.utils.StringUtils;
import com.sdhs.system.service.ISysDeptService;
import com.sdhs.system.service.ISysRoleService;
import com.sdhs.system.service.ISysUserService;
import com.sdhs.workflow.common.constant.FlowConstant;
import com.sdhs.workflow.common.enums.TaskStatusEnum;
import com.sdhs.workflow.common.enums.UnifyToDoExeTypeEnum;
import com.sdhs.workflow.domain.ActHiTaskinst;
import com.sdhs.workflow.domain.OssFile;
import com.sdhs.workflow.domain.WfTaskBackNode;
import com.sdhs.workflow.domain.bo.*;
import com.sdhs.workflow.domain.vo.*;
import com.sdhs.workflow.flowable.cmd.*;
import com.sdhs.workflow.flowable.handler.FlowProcessEventHandler;
import com.sdhs.workflow.mapper.ActHiTaskinstMapper;
import com.sdhs.workflow.mapper.ActTaskMapper;
import com.sdhs.workflow.service.*;
import com.sdhs.workflow.utils.ModelUtils;
import com.sdhs.workflow.utils.QueryUtils;
import com.sdhs.workflow.utils.WorkflowUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.flowable.engine.impl.persistence.entity.AttachmentEntity;
import org.flowable.engine.impl.persistence.entity.AttachmentEntityImpl;
import org.flowable.engine.impl.persistence.entity.AttachmentEntityManager;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.variable.api.persistence.entity.VariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.sdhs.workflow.common.constant.FlowConstant.*;

/**
 * 任务 服务层实现
 *
 * @author may
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class ActTaskServiceImpl implements IActTaskService {

    @Autowired(required = false)
    private RuntimeService runtimeService;
    @Autowired(required = false)
    private TaskService taskService;
    @Autowired(required = false)
    private HistoryService historyService;
    @Autowired(required = false)
    private IdentityService identityService;
    @Autowired(required = false)
    private ManagementService managementService;
    private final ActTaskMapper actTaskMapper;
    private final IWfTaskBackNodeService wfTaskBackNodeService;
    private final ActHiTaskinstMapper actHiTaskinstMapper;
    private final IWfNodeConfigService wfNodeConfigService;
    private final IWfDefinitionConfigService wfDefinitionConfigService;
    private final FlowProcessEventHandler flowProcessEventHandler;
    private final ISysUserService userService;
//    private final OssService ossService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private IWfApproveUserConfigService approveUserConfigService;

    @Autowired
    private ISysDeptService sysDeptService;

    /**
     * 启动任务
     *
     * @param startProcessBo 启动流程参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> startWorkFlow(StartProcessBo startProcessBo) {
        if (StringUtils.isBlank(startProcessBo.getBusinessId())) {
            throw new ServiceException("缺少业务数据唯一标识！");
        }

        Map<String, Object> map = new HashMap<>();
        if (StringUtils.isBlank(startProcessBo.getBusinessKey())) {
            startProcessBo.setBusinessKey(String.valueOf(IdWorker.getId()));
        }
        // 判断当前业务是否启动过流程
        HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery();
        HistoricProcessInstance historicProcessInstance = query.processInstanceBusinessKey(startProcessBo.getBusinessKey()).singleResult();
        if (ObjectUtil.isNotEmpty(historicProcessInstance)) {
            BusinessStatusEnum.checkStartStatus(historicProcessInstance.getBusinessStatus());
        }
        List<Task> taskResult = QueryUtils.taskQuery().processInstanceBusinessKey(startProcessBo.getBusinessKey()).list();
        if (CollUtil.isNotEmpty(taskResult)) {
            if (CollUtil.isNotEmpty(startProcessBo.getVariables())) {
                taskService.setVariables(taskResult.get(0).getId(), startProcessBo.getVariables());
            }
            map.put(PROCESS_INSTANCE_ID, taskResult.get(0).getProcessInstanceId());
            map.put("taskId", taskResult.get(0).getId());
            return map;
        }
        WfDefinitionConfigVo wfDefinitionConfigVo = wfDefinitionConfigService.getByTableNameLastVersion(startProcessBo.getTableName());
        if (wfDefinitionConfigVo == null) {
            throw new ServiceException("请到流程定义绑定业务表名与流程KEY！");
        }
        // 设置启动人
        identityService.setAuthenticatedUserId(SecurityUtils.getUserId());
        Authentication.setAuthenticatedUserId(SecurityUtils.getUserId());
        // 启动流程实例（提交申请）
        Map<String, Object> variables = startProcessBo.getVariables();
        // 启动跳过表达式
        variables.put(FLOWABLE_SKIP_EXPRESSION_ENABLED, true);
        // 流程发起人
        variables.put(INITIATOR, (SecurityUtils.getUserId()));
        variables.put(INITIATOR_NAME, (SecurityUtils.getNickName()));

        // 填充审批人 需求变更：2025-05-29 一个公司一套工作流，审批人员在流程中配置（角色）
//        List<WfApproveUserConfigVo> wfApproveUserConfigList = approveUserConfigService.queryList(new WfApproveUserConfigBo());
//        wfApproveUserConfigList.forEach(item -> {
//            if(StringUtils.isNotEmpty(item.getApproveNodeUserIds())){
//                variables.put(item.getApproveCode(), item.getApproveNodeUserIds());
//            }
//        });

//        // 填充项目经理
//        String projectManagerId = actTaskMapper.getProjectManagerId(startProcessBo.getTableName(), startProcessBo.getBusinessId());
//        if (StringUtils.isNotBlank(projectManagerId)) {
//            variables.put(ApproveCodeConfigEnum.PROJECT_MANAGER.getCode(), projectManagerId);
//        } else {
//            throw new ServiceException("请设置项目经理！");
//        }

        ProcessInstance pi;
        try {
            // 所属公司id
            String companyId = sysDeptService.selectCompanyIdtByUserId(SecurityUtils.getDeptId());
            pi = runtimeService.startProcessInstanceByKeyAndTenantId(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables, companyId);
        } catch (FlowableObjectNotFoundException e) {
            throw new ServiceException("找不到当前【" + wfDefinitionConfigVo.getProcessKey() + "】流程定义！");
        }

        // 更新业务表状态（已提交及待审核）
        flowProcessEventHandler.processHandler(
                wfDefinitionConfigVo.getProcessKey(),
                startProcessBo.getBusinessKey(),
                startProcessBo.getBusinessId(),
                BusinessStatusEnum.DRAFT.getStatus(),
                true
        );

        // 将流程定义名称 作为 流程实例名称
        runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName());
        // 申请人执行流程
        List<Task> taskList = QueryUtils.taskQuery(pi.getId()).list();
        if (taskList.size() > 1) {
            throw new ServiceException("请检查流程第一个环节是否为申请人！");
        }

        runtimeService.updateBusinessStatus(pi.getProcessInstanceId(), BusinessStatusEnum.DRAFT.getStatus());
        taskService.setAssignee(taskList.get(0).getId(), SecurityUtils.getUserId());
        taskService.setVariable(taskList.get(0).getId(), PROCESS_INSTANCE_ID, pi.getProcessInstanceId());
        taskService.setVariable(taskList.get(0).getId(), BUSINESS_KEY, pi.getBusinessKey());
        map.put("processInstanceId", pi.getProcessInstanceId());
        map.put("taskId", taskList.get(0).getId());

        // 申请人（审批流程）
        CompleteTaskBo completeTaskBo = new CompleteTaskBo();
        completeTaskBo.setTaskId(taskList.get(0).getId());
        completeTask(completeTaskBo);

        return map;
    }

    /**
     * 办理任务
     *
     * @param completeTaskBo 办理任务参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean completeTask(CompleteTaskBo completeTaskBo) {
        try {
            String userId = String.valueOf(SecurityUtils.getUserId());
            Task task = WorkflowUtils.getTaskByCurrentUser(completeTaskBo.getTaskId());
            if (task == null) {
                throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
            }
            if (task.isSuspended()) {
                throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
            }
            ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
            //办理委托任务
            if (ObjectUtil.isNotEmpty(task.getDelegationState()) && FlowConstant.PENDING.equals(task.getDelegationState().name())) {
                taskService.resolveTask(completeTaskBo.getTaskId());
                TaskEntity newTask = WorkflowUtils.createNewTask(task);
                taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isNotBlank(completeTaskBo.getMessage()) ? completeTaskBo.getMessage() : StrUtil.EMPTY);
                taskService.complete(newTask.getId());
                return true;
            }
            //附件上传
            List<OssFile> fileList = completeTaskBo.getFileList();
            if (fileList != null && !fileList.isEmpty()) {
                for (OssFile oss : fileList) {
                    AttachmentEntity attachmentEntity = new AttachmentEntityImpl();
                    attachmentEntity.setId(String.valueOf(IdWorker.getId()));
                    attachmentEntity.setRevision(1);
                    attachmentEntity.setUserId(SecurityUtils.getUserId());
                    attachmentEntity.setName(oss.getOriginalName());
                    attachmentEntity.setDescription(oss.getOriginalName());
                    attachmentEntity.setType(oss.getFileSuffix());
                    attachmentEntity.setTaskId(task.getId());
                    attachmentEntity.setProcessInstanceId(task.getProcessInstanceId());
                    attachmentEntity.setContentId(oss.getOssId().toString());
                    attachmentEntity.setUrl(oss.getUrl());
                    attachmentEntity.setTime(new Date());
                    actTaskMapper.insertAttachmentEntity(attachmentEntity);
                }
            }

            String businessStatus = WorkflowUtils.getBusinessStatus(processInstance.getBusinessKey());
            //流程提交监听
            if (BusinessStatusEnum.DRAFT.getStatus().equals(businessStatus) || BusinessStatusEnum.BACK.getStatus().equals(businessStatus) || BusinessStatusEnum.CANCEL.getStatus().equals(businessStatus)) {
                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(), businessStatus, true);
            }
            runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.WAITING.getStatus());
            //办理监听
            flowProcessEventHandler.processTaskHandler(processInstance.getProcessDefinitionKey(), task.getTaskDefinitionKey(),
                task.getId(), processInstance.getBusinessKey());
            //办理意见
            taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "同意" : completeTaskBo.getMessage());
            //办理任务
            taskService.setAssignee(task.getId(), userId);

            // 重新填充审批人（解决重新设置了审批人之后不生效问题） 需求变更：2025-05-29 一个公司一套工作流，审批人员在流程中配置（角色）
//            Map<String, Object> variables = completeTaskBo.getVariables();
//            if(variables == null){
//                variables = new HashMap<>();
//            }
//            List<WfApproveUserConfigVo> wfApproveUserConfigList = approveUserConfigService.queryList(new WfApproveUserConfigBo());
//            for (WfApproveUserConfigVo item : wfApproveUserConfigList) {
//                if(StringUtils.isNotEmpty(item.getApproveNodeUserIds())){
//                    variables.put(item.getApproveCode(), item.getApproveNodeUserIds());
//                }
//            }
//            completeTaskBo.setVariables(variables);

            try {
                if (CollUtil.isNotEmpty(completeTaskBo.getVariables())) {
                    taskService.complete(completeTaskBo.getTaskId(), completeTaskBo.getVariables());
                } else {
                    taskService.complete(completeTaskBo.getTaskId());
                }
            } catch (Exception e) {
                e.printStackTrace();
                if(e.getMessage().contains("${")){
                    throw new RuntimeException("请在【流程审批人配置】中配置审批人！");
                }

                throw new RuntimeException(e);
            }
            //记录执行过的流程任务节点
            wfTaskBackNodeService.recordExecuteNode(task);
            ProcessInstance pi = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
            if (pi == null) {
                UpdateBusinessStatusCmd updateBusinessStatusCmd = new UpdateBusinessStatusCmd(task.getProcessInstanceId(), BusinessStatusEnum.FINISH.getStatus());
                managementService.executeCommand(updateBusinessStatusCmd);
                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(),
                    BusinessStatusEnum.FINISH.getStatus(), false);
            } else {
                List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
                for (Task t : list) {
                    if (ModelUtils.isUserTask(t.getProcessDefinitionId(), t.getTaskDefinitionKey())) {
                        List<HistoricIdentityLink> links = historyService.getHistoricIdentityLinksForTask(t.getId());
                        if (CollUtil.isEmpty(links) && StringUtils.isBlank(t.getAssignee())) {
                            throw new ServiceException("下一节点【" + t.getName() + "】没有办理人!");
                        }
                    }
                }
                // 抄送
                if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(completeTaskBo.getWfCopyList())) {
                    TaskEntity newTask = WorkflowUtils.createNewTask(task);
                    taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), SecurityUtils.getLoginUser().getUser().getNickName() + "【抄送】给" + String.join(",", StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserName)));
                    taskService.complete(newTask.getId());
                    List<Task> taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
                    WorkflowUtils.createCopyTask(taskList, StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserId));
                }

                handleToDoAndSendMsg(processInstance, list, task, null);
            }
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     *  处理待办和发送消息
     * @param processInstance 流程实例
     * @param list 要办理的任务
     * @param task 当前任务
     * @param msg 消息
     */
    private void handleToDoAndSendMsg(ProcessInstance processInstance, List<Task> list, Task task, String msg) {
        String code = processInstance.getBusinessKey();
        Map<String, Object> variableMap = runtimeService.getVariables(processInstance.getId());
        String initiator = (String) variableMap.get(INITIATOR);
        String initiatorName = (String) variableMap.get(INITIATOR_NAME);
        Map<String, Object> entity = (Map<String, Object>) variableMap.get(ENTITY);
        String businessId = entity.get(BUSINESS_ID) != null ? entity.get(BUSINESS_ID).toString() : null;

        List<String> users = WorkflowUtils.getUsersByTask(list,userService);

        // 创建待办
        WorkflowUtils.processTask2Unify(list, processInstance.getName(),  users, UnifyToDoExeTypeEnum.TO_DO_ADD.getCode(), code, initiator, initiatorName,businessId);

        if(!initiator.equals(SecurityUtils.getUserId())){
            // 修改待办
            WorkflowUtils.processTask2Unify(
                    Collections.singletonList(task),
                    processInstance.getName(),
                    Collections.singletonList(SecurityUtils.getUserId()),
                    UnifyToDoExeTypeEnum.TO_DO_SET.getCode(),
                    code,
                    initiator,
                    initiatorName,
                    businessId
            );
        }

        // 发送消息
        WorkflowUtils.sendMessage(list, processInstance.getName(), users, code, initiator, initiatorName,businessId);
    }

    /**
     * 查询当前用户的待办任务
     *
     * @param taskBo 参数
     */
    @Override
    public TableDataInfo getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) {

        SysUser user = SecurityUtils.getLoginUser().getUser();
        List<Long> roleIds = roleService.selectRoleListByUserId(user.getUserId());
        String userId = String.valueOf(SecurityUtils.getUserId());

        taskBo.setUserId(userId);
        taskBo.setRoleIds(StreamUtils.join(roleIds, x -> "'" + x + "'"));

        Page<TaskVo> page = actTaskMapper.getTaskWaitByPage(pageQuery.build(), taskBo);

        List<TaskVo> taskList = page.getRecords();
        if (CollUtil.isNotEmpty(taskList)) {
            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);

            List<String> procInstIds = StreamUtils.toList(taskList, TaskVo::getProcessInstanceId);
            List<TaskVo> startUserList = actTaskMapper.selectStartUserByProcInstIds(procInstIds);
            Map<String, TaskVo> startUserMap = new HashMap<>();
            startUserList.forEach(e -> startUserMap.put(e.getProcessInstanceId(), e));

            for (TaskVo task : taskList) {
                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
//                task.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId(), userService));
                task.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
                }

                if (startUserMap.containsKey(task.getProcessInstanceId())) {
                    task.setAssignee(startUserMap.get(task.getProcessInstanceId()).getAssignee());
                    task.setAssigneeName(startUserMap.get(task.getProcessInstanceId()).getAssigneeName());
                }
            }
        }
        return TableDataInfo.build(page);
    }

    @Override
    public TaskVo getToDoByTaskWaitByBusinessKey(String businessKey) {
        List<TaskVo> taskList = actTaskMapper.getToDoByTaskWaitByBusinessKey(businessKey);
        if(taskList == null || taskList.isEmpty()){
            return null;
        }

        TaskVo task = taskList.get(0);

        List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(Collections.singletonList(task.getProcessDefinitionId()));
        List<TaskVo> startUserList = actTaskMapper.selectStartUserByProcInstIds(Collections.singletonList(task.getProcessInstanceId()));
        Map<String, TaskVo> startUserMap = new HashMap<>();
        startUserList.forEach(e -> startUserMap.put(e.getProcessInstanceId(), e));

        task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
//                task.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId(), userService));
        task.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
        if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
            wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
            wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
        }

        if (startUserMap.containsKey(task.getProcessInstanceId())) {
            task.setAssignee(startUserMap.get(task.getProcessInstanceId()).getAssignee());
            task.setAssigneeName(startUserMap.get(task.getProcessInstanceId()).getAssigneeName());
        }
        return task;
    }

    @Override
    public TaskVo getTaskWaitByBusinessKey(String businessKey) {
        List<TaskVo> taskList = actTaskMapper.getToDoByTaskWaitByBusinessKey(businessKey);
        if(taskList == null || taskList.isEmpty()){
            return null;
        }

        TaskVo task = null;

        for(TaskVo item : taskList){
            ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(item.getId(), userService);
            if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
                item.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
                if(item.getAssignee() != null && item.getAssignee().contains(SecurityUtils.getUserId())){
                    task = item;
                    break;
                }
            }
        }

        if(task == null){
            throw new ServiceException("当前登录人没有该流程的待办任务");
        }

        List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(Collections.singletonList(task.getProcessDefinitionId()));
        List<TaskVo> startUserList = actTaskMapper.selectStartUserByProcInstIds(Collections.singletonList(task.getProcessInstanceId()));
        Map<String, TaskVo> startUserMap = new HashMap<>();
        startUserList.forEach(e -> startUserMap.put(e.getProcessInstanceId(), e));

        task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
        task.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
        if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
            TaskVo finalTask = task;
            wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(finalTask.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
            wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(finalTask.getProcessDefinitionId()) && e.getNodeId().equals(finalTask.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
        }

        if (startUserMap.containsKey(task.getProcessInstanceId())) {
            task.setStartUserId(startUserMap.get(task.getProcessInstanceId()).getAssignee());
            task.setStartUserName(startUserMap.get(task.getProcessInstanceId()).getAssigneeName());
        }
        return task;
    }

    @Override
    public List<TaskVo> getToDoByTaskWaitByBusinessKeyAndUserId(String businessKey) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        List<Long> roleIds = roleService.selectRoleListByUserId(user.getUserId());
        String userId = String.valueOf(SecurityUtils.getUserId());

        TaskBo taskBo = new TaskBo();
        taskBo.setUserId(userId);
        taskBo.setRoleIds(StreamUtils.join(roleIds, x -> x + ""));
        taskBo.setBusinessKey(businessKey);
        return actTaskMapper.getToDoByTaskWaitByBusinessKeyAndUserId(taskBo);
    }

    /**
     * 查询当前租户所有待办任务
     *
     * @param taskBo 参数
     */
    @Override
    public TableDataInfo getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) {
        TaskQuery query = QueryUtils.taskQuery();
        if (StringUtils.isNotBlank(taskBo.getName())) {
            query.taskNameLike("%" + taskBo.getName() + "%");
        }
        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
            query.processDefinitionNameLike("%" + taskBo.getProcessDefinitionName() + "%");
        }
        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
            query.processDefinitionKey(taskBo.getProcessDefinitionKey());
        }
        query.orderByTaskCreateTime().desc();
        List<Task> taskList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
        List<ProcessInstance> processInstanceList = null;
        if (CollUtil.isNotEmpty(taskList)) {
            Set<String> processInstanceIds = StreamUtils.toSet(taskList, Task::getProcessInstanceId);
            processInstanceList = QueryUtils.instanceQuery(processInstanceIds).list();
        }
        List<TaskVo> list = new ArrayList<>();
        if (CollUtil.isNotEmpty(taskList)) {
            List<String> processDefinitionIds = StreamUtils.toList(taskList, Task::getProcessDefinitionId);
            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
            for (Task task : taskList) {
                TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class);
                if (CollUtil.isNotEmpty(processInstanceList)) {
                    processInstanceList.stream().filter(e -> e.getId().equals(task.getProcessInstanceId())).findFirst().ifPresent(e -> {
                        taskVo.setBusinessStatus(e.getBusinessStatus());
                        taskVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(taskVo.getBusinessStatus()));
                        taskVo.setProcessDefinitionKey(e.getProcessDefinitionKey());
                        taskVo.setProcessDefinitionName(e.getProcessDefinitionName());
                        taskVo.setProcessDefinitionVersion(e.getProcessDefinitionVersion());
                        taskVo.setBusinessKey(e.getBusinessKey());
                    });
                }
                taskVo.setAssignee(StringUtils.isNotBlank(task.getAssignee()) ? task.getAssignee() : null);
//                taskVo.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId(), userService));
                taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo);
                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo);
                }
                list.add(taskVo);
            }
        }
        long count = query.count();
        TableDataInfo build = TableDataInfo.build();
        build.setRows(list);
        build.setTotal(count);
        return build;
    }

    /**
     * 查询当前用户的已办任务
     *
     * @param taskBo 参数
     */
    @Override
    public TableDataInfo getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
        taskBo.setUserId(SecurityUtils.getUserId());
        Page<TaskVo> page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), taskBo);

        List<TaskVo> taskList = page.getRecords();
        if (CollUtil.isNotEmpty(taskList)) {
            // 查询办理人
            List<String> assigneeIds = StreamUtils.toList(taskList, TaskVo::getAssignee);
            List<SysUser> assigneeList = userService.selectListByIds(assigneeIds);
            Map<String, SysUser> assigneeMap = StreamUtils.toMap(assigneeList, SysUser::getUserId, (e) -> e);
            // 查询发起人
            List<String> startUserIds = StreamUtils.toList(taskList, TaskVo::getStartUserId);
            List<SysUser> startUserList = userService.selectListByIds(startUserIds);
            Map<String, SysUser> startUserMap = StreamUtils.toMap(startUserList, SysUser::getUserId, (e) -> e);

            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
            for (TaskVo task : taskList) {
                task.setAssigneeName(assigneeMap.get(task.getAssignee()).getNickName());
                task.setStartUserName(startUserMap.get(task.getStartUserId()).getNickName());

                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
                }
            }
        }
        return TableDataInfo.build(page);
    }

    /**
     * 查询当前用户的抄送
     *
     * @param taskBo 参数
     */
    @Override
    public TableDataInfo getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) {
        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
        String userId = String.valueOf(SecurityUtils.getUserId());
        if (StringUtils.isNotBlank(taskBo.getName())) {
            queryWrapper.like("t.name_", taskBo.getName());
        }
        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
            queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName());
        }
        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
            queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey());
        }
        queryWrapper.eq("t.assignee_", userId);
        Page<TaskVo> page = actTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper);

        List<TaskVo> taskList = page.getRecords();
        if (CollUtil.isNotEmpty(taskList)) {
            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
            for (TaskVo task : taskList) {
                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
                }
            }
        }
        return TableDataInfo.build(page);
    }

    /**
     * 查询当前租户所有已办任务
     *
     * @param taskBo 参数
     */
    @Override
    public TableDataInfo getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
        Page<TaskVo> page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), taskBo);

        List<TaskVo> taskList = page.getRecords();
        if (CollUtil.isNotEmpty(taskList)) {
            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
            for (TaskVo task : taskList) {
                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
                }
            }
        }
        return TableDataInfo.build(page);
    }

    /**
     * 委派任务
     *
     * @param delegateBo 参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delegateTask(DelegateBo delegateBo) {
        Task task = WorkflowUtils.getTaskByCurrentUser(delegateBo.getTaskId());

        if (ObjectUtil.isEmpty(task)) {
            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
        }
        if (task.isSuspended()) {
            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
        }
        try {
            TaskEntity newTask = WorkflowUtils.createNewTask(task);
            taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PENDING.getStatus(), "【" + SecurityUtils.getLoginUser().getUser().getNickName() + "】委派给【" + delegateBo.getNickName() + "】");
            //委托任务
            taskService.delegateTask(delegateBo.getTaskId(), delegateBo.getUserId());
            //办理生成的任务记录
            taskService.complete(newTask.getId());
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 终止任务
     *
     * @param terminationBo 参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean terminationTask(TerminationBo terminationBo) {
        TaskQuery query = QueryUtils.taskQuery();
        Task task = query.taskId(terminationBo.getTaskId()).singleResult();

        if (ObjectUtil.isEmpty(task)) {
            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
        }
        if (task.isSuspended()) {
            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
        }
        HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus());
        try {
            if (StringUtils.isBlank(terminationBo.getComment())) {
                terminationBo.setComment(SecurityUtils.getLoginUser().getUser().getNickName() + "终止了申请");
            } else {
                terminationBo.setComment(SecurityUtils.getLoginUser().getUser().getNickName() + "终止了申请：" + terminationBo.getComment());
            }
            taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TERMINATION.getStatus(), terminationBo.getComment());
            List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
            if (CollUtil.isNotEmpty(list)) {
                List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
                if (CollUtil.isNotEmpty(subTasks)) {
                    subTasks.forEach(e -> taskService.deleteTask(e.getId()));
                }
                runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.TERMINATION.getStatus());
                runtimeService.deleteProcessInstance(task.getProcessInstanceId(), StrUtil.EMPTY);
            }
            //流程终止监听
            flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(),
                historicProcessInstance.getBusinessKey(), BusinessStatusEnum.TERMINATION.getStatus(), false);
            return true;
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 转办任务
     *
     * @param transmitBo 参数
     */
    @Override
    public boolean transferTask(TransmitBo transmitBo) {
        Task task = WorkflowUtils.getTaskByCurrentUser(transmitBo.getTaskId());
        if (ObjectUtil.isEmpty(task)) {
            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
        }
        if (task.isSuspended()) {
            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
        }
        try {
            TaskEntity newTask = WorkflowUtils.createNewTask(task);
            taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.TRANSFER.getStatus(), StringUtils.isNotBlank(transmitBo.getComment()) ? transmitBo.getComment() : SecurityUtils.getLoginUser().getUser().getNickName() + "转办了任务");
            taskService.complete(newTask.getId());
            taskService.setAssignee(task.getId(), transmitBo.getUserId());
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 会签任务加签
     *
     * @param addMultiBo 参数
     */
    @Override
    public boolean addMultiInstanceExecution(AddMultiBo addMultiBo) {
        TaskQuery taskQuery = QueryUtils.taskQuery();
        taskQuery.taskId(addMultiBo.getTaskId());
        if (!SecurityUtils.isAdmin(SecurityUtils.getUserId())) {
            taskQuery.taskCandidateOrAssigned(String.valueOf(SecurityUtils.getUserId()));
        }
        Task task = taskQuery.singleResult();
        if (ObjectUtil.isEmpty(task)) {
            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
        }
        if (task.isSuspended()) {
            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
        }
        String taskDefinitionKey = task.getTaskDefinitionKey();
        String processInstanceId = task.getProcessInstanceId();
        String processDefinitionId = task.getProcessDefinitionId();

        try {
            MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey);
            if (multiInstanceVo == null) {
                throw new ServiceException("当前环节不是会签节点");
            }
            if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) {
                for (Long assignee : addMultiBo.getAssignees()) {
                    runtimeService.addMultiInstanceExecution(taskDefinitionKey, processInstanceId, Collections.singletonMap(multiInstanceVo.getAssignee(), assignee));
                }
            } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) {
                AddSequenceMultiInstanceCmd addSequenceMultiInstanceCmd = new AddSequenceMultiInstanceCmd(task.getExecutionId(), multiInstanceVo.getAssigneeList(), addMultiBo.getAssignees());
                managementService.executeCommand(addSequenceMultiInstanceCmd);
            }
            List<String> assigneeNames = addMultiBo.getAssigneeNames();
            String username = SecurityUtils.getUsername();
            TaskEntity newTask = WorkflowUtils.createNewTask(task);
            taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN.getStatus(), username + "加签【" + String.join(StringUtils.SEPARATOR, assigneeNames) + "】");
            taskService.complete(newTask.getId());
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 会签任务减签
     *
     * @param deleteMultiBo 参数
     */
    @Override
    public boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo) {
        TaskQuery taskQuery = QueryUtils.taskQuery();
        taskQuery.taskId(deleteMultiBo.getTaskId());
        if (!SecurityUtils.isAdmin(SecurityUtils.getUserId())) {
            taskQuery.taskCandidateOrAssigned(String.valueOf(SecurityUtils.getUserId()));
        }
        Task task = taskQuery.singleResult();
        if (ObjectUtil.isEmpty(task)) {
            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
        }
        if (task.isSuspended()) {
            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
        }
        String taskDefinitionKey = task.getTaskDefinitionKey();
        String processInstanceId = task.getProcessInstanceId();
        String processDefinitionId = task.getProcessDefinitionId();
        try {
            MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey);
            if (multiInstanceVo == null) {
                throw new ServiceException("当前环节不是会签节点");
            }
            if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) {
                for (String executionId : deleteMultiBo.getExecutionIds()) {
                    runtimeService.deleteMultiInstanceExecution(executionId, false);
                }
                for (String taskId : deleteMultiBo.getTaskIds()) {
                    historyService.deleteHistoricTaskInstance(taskId);
                }
            } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) {
                DeleteSequenceMultiInstanceCmd deleteSequenceMultiInstanceCmd = new DeleteSequenceMultiInstanceCmd(task.getAssignee(), task.getExecutionId(), multiInstanceVo.getAssigneeList(), deleteMultiBo.getAssigneeIds());
                managementService.executeCommand(deleteSequenceMultiInstanceCmd);
            }
            List<String> assigneeNames = deleteMultiBo.getAssigneeNames();
            String username = SecurityUtils.getUsername();
            TaskEntity newTask = WorkflowUtils.createNewTask(task);
            taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN_OFF.getStatus(), username + "减签【" + String.join(StringUtils.SEPARATOR, assigneeNames) + "】");
            taskService.complete(newTask.getId());
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 驳回审批
     *
     * @param backProcessBo 参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String backProcess(BackProcessBo backProcessBo) {
        String userId = String.valueOf(SecurityUtils.getUserId());
        Task task = WorkflowUtils.getTaskByCurrentUser(backProcessBo.getTaskId());

        if (ObjectUtil.isEmpty(task)) {
            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
        }
        if (task.isSuspended()) {
            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
        }
        try {
            String processInstanceId = task.getProcessInstanceId();
            ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
            //获取并行网关执行后保留的执行实例数据
            ExecutionChildByExecutionIdCmd childByExecutionIdCmd = new ExecutionChildByExecutionIdCmd(task.getExecutionId());
            List<ExecutionEntity> executionEntities = managementService.executeCommand(childByExecutionIdCmd);
            //校验单据
            BusinessStatusEnum.checkBackStatus(processInstance.getBusinessStatus());
            //判断是否有多个任务
            List<Task> taskList = QueryUtils.taskQuery(processInstanceId).list();
            String backTaskDefinitionKey = backProcessBo.getTargetActivityId();
            // 如果未指定驳回的节点，则默认第一个节点（申请人节点）
            if(StringUtils.isEmpty(backTaskDefinitionKey)){
                HistoricTaskInstance firstTask = historyService.createHistoricTaskInstanceQuery()
                        .processInstanceId(processInstanceId)
                        .orderByHistoricTaskInstanceStartTime().asc()
                        .list()
                        .get(0);
                backTaskDefinitionKey = firstTask.getTaskDefinitionKey();
            }

            //附件上传
            List<OssFile> fileList = backProcessBo.getFileList();
            if (fileList != null && !fileList.isEmpty()) {
                for (OssFile oss : fileList) {
                    AttachmentEntity attachmentEntity = new AttachmentEntityImpl();
                    attachmentEntity.setId(String.valueOf(IdWorker.getId()));
                    attachmentEntity.setRevision(1);
                    attachmentEntity.setUserId(SecurityUtils.getUserId());
                    attachmentEntity.setName(oss.getOriginalName());
                    attachmentEntity.setDescription(oss.getOriginalName());
                    attachmentEntity.setType(oss.getFileSuffix());
                    attachmentEntity.setTaskId(task.getId());
                    attachmentEntity.setProcessInstanceId(task.getProcessInstanceId());
                    attachmentEntity.setContentId(oss.getOssId().toString());
                    attachmentEntity.setUrl(oss.getUrl());
                    attachmentEntity.setTime(new Date());
                    actTaskMapper.insertAttachmentEntity(attachmentEntity);
                }
            }

            // 设置当前任务办理人为 当前登录用户
            taskService.setAssignee(task.getId(), userId);

            taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.BACK.getStatus(), StringUtils.isNotBlank(backProcessBo.getMessage()) ? backProcessBo.getMessage() : "退回");
            if (taskList.size() > 1) {
                //当前多个任务驳回到单个节点
                runtimeService.createChangeActivityStateBuilder()
                        .processInstanceId(processInstanceId)
                        .moveActivityIdsToSingleActivityId(taskList.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList()), backTaskDefinitionKey)
                        .changeState();
                ActHiTaskinst actHiTaskinst = new ActHiTaskinst();
                actHiTaskinst.setAssignee(userId);
                actHiTaskinst.setId(task.getId());
                actHiTaskinstMapper.updateById(actHiTaskinst);
            } else {
                //当前单个节点驳回单个节点
                runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdTo(task.getTaskDefinitionKey(), backTaskDefinitionKey).changeState();
            }
            //删除并行环节未办理记录
            MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
            if (multiInstance == null && taskList.size() > 1) {
                List<Task> tasks = StreamUtils.filter(taskList, e -> !e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
                if (CollUtil.isNotEmpty(tasks)) {
                    actHiTaskinstMapper.deleteByIds(StreamUtils.toList(tasks, Task::getId));
                }
            }


            List<HistoricTaskInstance> instanceList = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().desc().list();
            List<Task> list = QueryUtils.taskQuery(processInstanceId).list();
            for (Task t : list) {
                instanceList.stream().filter(e -> e.getTaskDefinitionKey().equals(t.getTaskDefinitionKey())).findFirst().ifPresent(e -> {
                    taskService.setAssignee(t.getId(), e.getAssignee());
                });
            }

            //删除流程实例垃圾数据
            for (ExecutionEntity executionEntity : executionEntities) {
                DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId());
                managementService.executeCommand(deleteExecutionCmd);
            }

            WfTaskBackNode wfTaskBackNode = wfTaskBackNodeService.getListByInstanceIdAndNodeId(task.getProcessInstanceId(), backTaskDefinitionKey);
            if (ObjectUtil.isNotNull(wfTaskBackNode) && wfTaskBackNode.getOrderNo() == 0) {
                runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus());
                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(),
                    processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false);
            }
            //删除驳回后的流程节点
            wfTaskBackNodeService.deleteBackTaskNode(processInstanceId, backTaskDefinitionKey);

            //------modefy by stk
            //发送消息
            String message = "您的【" + processInstance.getName() + "】单据已经被驳回，请您及时处理。";
            handleToDoAndSendMsgForBack(processInstance, task, message);
            //------modefy by stk
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(e.getMessage());
        }
        return task.getProcessInstanceId();
    }


    /**
     *  处理待办和发送消息
     * @param processInstance 流程实例
     * @param task 当前任务
     * @param msg 消息
     */
    private void handleToDoAndSendMsgForBack(ProcessInstance processInstance, Task task, String msg) {
        String code = processInstance.getBusinessKey();
        Map<String, Object> variableMap = runtimeService.getVariables(processInstance.getId());
        String initiator = (String) variableMap.get(INITIATOR);
        String initiatorName = (String) variableMap.get(INITIATOR_NAME);
        Map<String, Object> entity = (Map<String, Object>) variableMap.get(ENTITY);
        String businessId = entity.get(BUSINESS_ID) != null ? entity.get(BUSINESS_ID).toString() : null;

        if(!initiator.equals(SecurityUtils.getUserId())){
            // 修改待办
            WorkflowUtils.processTask2Unify(
                    Collections.singletonList(task),
                    processInstance.getName(),
                    Collections.singletonList(SecurityUtils.getUserId()),
                    UnifyToDoExeTypeEnum.TO_DO_SET.getCode(),
                    code,
                    initiator,
                    initiatorName,
                    businessId
            );
        }

        // 发送消息
        WorkflowUtils.sendMessage(List.of(task), processInstance.getName(), List.of(initiator), code, initiator, initiatorName,businessId, msg);
    }

    /**
     * 修改任务办理人
     *
     * @param taskIds 任务id
     * @param userId  办理人id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateAssignee(String[] taskIds, String userId) {
        try {
            List<Task> list = QueryUtils.taskQuery().taskIds(Arrays.asList(taskIds)).list();
            for (Task task : list) {
                taskService.setAssignee(task.getId(), userId);
            }
        } catch (Exception e) {
            log.error("修改失败：" + e.getMessage(), e);
            throw new ServiceException("修改失败：" + e.getMessage());
        }
        return true;
    }

    /**
     * 查询流程变量
     *
     * @param taskId 任务id
     */
    @Override
    public List<VariableVo> getInstanceVariable(String taskId) {
        List<VariableVo> variableVoList = new ArrayList<>();
        Map<String, VariableInstance> variableInstances = taskService.getVariableInstances(taskId);
        if (CollUtil.isNotEmpty(variableInstances)) {
            for (Map.Entry<String, VariableInstance> entry : variableInstances.entrySet()) {
                VariableVo variableVo = new VariableVo();
                variableVo.setKey(entry.getKey());
                variableVo.setValue(entry.getValue().getValue().toString());
                variableVoList.add(variableVo);
            }
        }
        return variableVoList;
    }

    /**
     * 查询工作流任务用户选择加签人员
     *
     * @param taskId 任务id
     * @return
     */
    @Override
    @SuppressWarnings("unchecked")
    public String getTaskUserIdsByAddMultiInstance(String taskId) {
        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new ServiceException("任务不存在");
        }
        MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
        if (multiInstance == null) {
            return "";
        }
        List<Long> userIds;
        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
            userIds = (List<Long>) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList());
        } else {
            List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
            userIds = StreamUtils.toList(list, e -> Long.valueOf(e.getAssignee()));
        }
        return StringUtils.join(userIds, StringUtils.SEPARATOR);
    }

    /**
     * 查询工作流选择减签人员
     *
     * @param taskId 任务id 任务id
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<TaskVo> getListByDeleteMultiInstance(String taskId) {
        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
        List<Task> taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
        MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
        List<TaskVo> taskListVo = new ArrayList<>();
        if (multiInstance == null) {
            return List.of();
        }
        List<String> assigneeList = new ArrayList<>();
        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
            List<Object> variable = (List<Object>) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList());
            for (Object o : variable) {
                assigneeList.add(o.toString());
            }
        }

        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
            List<String> userIds = StreamUtils.filter(assigneeList, e -> !String.valueOf(e).equals(task.getAssignee()));
            List<SysUser> userList = userService.selectListByIds(userIds);
            for (String userId : userIds) {
                TaskVo taskVo = new TaskVo();
                taskVo.setId("串行会签");
                taskVo.setExecutionId("串行会签");
                taskVo.setProcessInstanceId(task.getProcessInstanceId());
                taskVo.setName(task.getName());
                taskVo.setAssignee(userId);
                if (CollUtil.isNotEmpty(userList)) {
                    userList.stream().filter(u -> u.getUserId().toString().equals(userId.toString())).findFirst().ifPresent(u -> taskVo.setAssigneeName(u.getNickName()));
                }
                taskListVo.add(taskVo);
            }
            return taskListVo;
        } else if (multiInstance.getType() instanceof ParallelMultiInstanceBehavior) {
            List<Task> tasks = StreamUtils.filter(taskList, e -> StringUtils.isBlank(e.getParentTaskId()) && !e.getExecutionId().equals(task.getExecutionId()) && e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
            if (CollUtil.isNotEmpty(tasks)) {
                List<String> userIds = StreamUtils.toList(tasks, e -> e.getAssignee());
                List<SysUser> userList = userService.selectListByIds(userIds);
                for (Task t : tasks) {
                    TaskVo taskVo = new TaskVo();
                    taskVo.setId(t.getId());
                    taskVo.setExecutionId(t.getExecutionId());
                    taskVo.setProcessInstanceId(t.getProcessInstanceId());
                    taskVo.setName(t.getName());
                    taskVo.setAssignee(t.getAssignee());
                    if (CollUtil.isNotEmpty(userList)) {
                        userList.stream().filter(u -> u.getUserId().toString().equals(t.getAssignee())).findFirst().ifPresent(e -> taskVo.setAssigneeName(e.getNickName()));
                    }
                    taskListVo.add(taskVo);
                }
                return taskListVo;
            }
        }
        return List.of();
    }


    /**
     * 总体流程监听(例如: 提交 退回 撤销 终止 作废等)
     * 正常使用只需#processEvent.key=='leave1'
     * 示例为了方便则使用startsWith匹配了全部示例key
     *
     * @param processEvent 参数
     */
    @org.springframework.context.event.EventListener(condition = "#processEvent.key!=null")
    public void processHandler(ProcessEvent processEvent) {
//        List<String> processKeys = List.of(
//                "project_cost",
//                "project_assessment_appeal",
//                "project_changes",
//                "procurement_plan_formulation",
//                "overall_plan_formulation",
//                "overall_plan_change",
//                "construction_organization_plan",
//                "joint_design",
//                "project_department_set_up",
//                "progress_hand_in",
//                "progress_completion_on",
//                "manage_list",
//                "progress_project_end",
//                "project_other",
//                "project_start_work"
//        );
        WfDefinitionConfigVo wfDefinitionConfigVo = wfDefinitionConfigService.getByProcessKeyLastVersion(processEvent.getKey());

        if (wfDefinitionConfigVo == null) {
            return;
        }

        String approvalStatus = null;
//        if (processKeys.contains(processEvent.getKey())) {
            // 已提交
            if (processEvent.isSubmit()) {
                approvalStatus = BusinessStatusEnum.WAITING.getStatusValue();
            }

            // 已撤销
            if (BusinessStatusEnum.CANCEL.getStatus().equals(processEvent.getStatus())) {
                approvalStatus = BusinessStatusEnum.CANCEL.getStatusValue();
            }
            // 已终止
            if (BusinessStatusEnum.TERMINATION.getStatus().equals(processEvent.getStatus())) {
                approvalStatus = BusinessStatusEnum.TERMINATION.getStatusValue();
            }
            // 已作废
            if (BusinessStatusEnum.INVALID.getStatus().equals(processEvent.getStatus())) {
                approvalStatus = BusinessStatusEnum.INVALID.getStatusValue();
            }
            // 已退回
            if (BusinessStatusEnum.BACK.getStatus().equals(processEvent.getStatus())) {
                approvalStatus = BusinessStatusEnum.BACK.getStatusValue();
            }
            // 已完成（已通过）
            if (BusinessStatusEnum.FINISH.getStatus().equals(processEvent.getStatus())) {
                approvalStatus = BusinessStatusEnum.FINISH.getStatusValue();
            }
            // 审批中
            if (BusinessStatusEnum.WAITING.getStatus().equals(processEvent.getStatus())) {
                approvalStatus = BusinessStatusEnum.WAITING.getStatusValue();
            }
//        }
        if (approvalStatus != null) {
            if(StringUtils.isNotEmpty(processEvent.getBusinessId())){
                actTaskMapper.updateBusinessDataStatusByBusinessId(wfDefinitionConfigVo.getTableName(), processEvent.getBusinessId(), processEvent.getBusinessKey(), approvalStatus);
            }else{
                actTaskMapper.updateBusinessDataStatusByBusinessKey(wfDefinitionConfigVo.getTableName(), processEvent.getBusinessKey(), approvalStatus);
            }

            actTaskMapper.updateMessageStatusByBusinessKeyAndReceiver(Long.valueOf(processEvent.getBusinessKey()), SecurityUtils.getUsername());
        }
    }

    /**
     * 执行办理任务监听
     * 示例：也可通过  @EventListener(condition = "#processTaskEvent.key=='leave1'")进行判断
     * 在方法中判断流程节点key
     * if ("xxx".equals(processTaskEvent.getTaskDefinitionKey())) {
     * //执行业务逻辑
     * }
     *
     * @param processTaskEvent 参数
     */
    @EventListener(condition = "#processTaskEvent.key!=null")
    public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
//        List<String> processKeys = List.of(
//                "project_cost",
//                "project_assessment_appeal",
//                "project_changes",
//                "procurement_plan_formulation",
//                "overall_plan_formulation",
//                "overall_plan_change",
//                "construction_organization_plan",
//                "joint_design",
//                "project_department_set_up",
//                "progress_hand_in",
//                "progress_completion_on",
//                "manage_list",
//                "progress_project_end",
//                "project_other",
//                "project_start_work"
//        );
        WfDefinitionConfigVo wfDefinitionConfigVo = wfDefinitionConfigService.getByProcessKeyLastVersion(processTaskEvent.getKey());

        if (wfDefinitionConfigVo == null) {
            return;
        }

        String approvalStatus = null;
//        if (processKeys.contains(processTaskEvent.getKey())) {
            approvalStatus = BusinessStatusEnum.WAITING.getStatusValue();
//        }

//        if (approvalStatus != null) {
            if(StringUtils.isNotEmpty(processTaskEvent.getBusinessId())){
                actTaskMapper.updateBusinessDataStatusByBusinessId(wfDefinitionConfigVo.getTableName(), processTaskEvent.getBusinessId(), processTaskEvent.getBusinessKey(), approvalStatus);
            }else{
                actTaskMapper.updateBusinessDataStatusByBusinessKey(wfDefinitionConfigVo.getTableName(), processTaskEvent.getBusinessKey(), approvalStatus);
            }

            actTaskMapper.updateMessageStatusByBusinessKeyAndReceiver(Long.valueOf(processTaskEvent.getBusinessKey()), SecurityUtils.getUsername());
//        }
    }
}
